home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
ab20
/
hardware
/
ioexpnsn.lzh
/
NewPAR
/
NewPar.asm
< prev
Wrap
Assembly Source File
|
1991-01-28
|
26KB
|
901 lines
*****************************************************************************
* Program: eightbit.asm - Copyright ©1990,91 DigiSoft
* Function: A "parallel.device" compatible driver for the Rockwell 65C22
*
* Author: Paul Coward ©1990 DigiSoft
* History: 11/12/90 PC V0.50 Adapted from Sharer project to suit independent
* IO PD project initiated by Jeff Lavin.
* 01/14/91 PC V0.53 Finally !!!
*
* [To all: Please don't forget to bump the revision numbers
* if you do *any* modifications at all. -Jeff]
*****************************************************************************
** Tabstops : 8
** Assemble with Macro68
ifnd __m68
fail 'Wrong assembler!'
endc
exeobj
incpath Includes:
macfile IOexp.i ;The One & Only include file
objfile ram:eightbit.device
; Name P2 Centronics (VIA_1)
; ==== == ==========
; CA2.2 2 1 STROBE*
; PA0.2 3 2 DATA0
; PA1.2 4 3 DATA1
; PA2.2 5 4 DATA2
; PA3.2 6 5 DATA3
; PA4.2 7 6 DATA4
; PA5.2 8 7 DATA5
; PA6.2 9 8 DATA6
; PA7.2 10 9 DATA7
; CA1.2 1 10 ACK*
; GND PAD 16 GND
*****************************************************************************
* Everything in this block will eventually be transferred to ioexp.i *
*****************************************************************************
PVERSION equ 1 ;major version number
PREVISION equ 6 ;minor version number
pcrBits equ %10101010 ;pulse output
ierABits equ %00000010 ;CA1
ierBBits equ %00010000 ;CB1
IOR equ 0
DDR equ DDRA-ORA
cdPri equ 5
mduStackSize equ $200
mdTaskPri equ 5
; --- Unit flags - pdu_devFlags
BITDEF rw,EOFMODE,0 ;unit read/write flag
BITDEF rw,NULLMODE,1 ;unit read/write null terminated flag
BITDEF io,SHARED,2 ;unit shared access allowed
; my device data area structure
setso LIB_SIZE
dev_Flags so.b 1
dev_MyFlags so.b 1
dev_SegList so.l 1
dev_Units so.b MD_NUMUNITS*4
dev_SizeOf soval
setso UNIT_SIZE
pdu_UnitNum so.b 1
pdu_devFlags so.b 1
pdu_IOparFlags so.b 1
alignso 0,4
pdu_stack so.b mduStackSize
pdu_tcb so.b TC_SIZE
pdu_Device so.l 1
pdu_HardwareBase so.l 1
pdu_IOReg so.w 1
pdu_ifrMask so.w 1
pdu_SigMask so.l 1
pdu_is so.b IS_SIZE
pdu_rwBufferLocation so.l 1
pdu_lengthCounter so.l 1
pdu_CurrentIOB so.l 1
pdu_TermArray soval
pdu_TermArray_0 so.b (PTERMARRAY_SIZE/2)
pdu_TermArray_1 so.b (PTERMARRAY_SIZE/2)
pdu_Sizeof soval
BITDEF DEV,ACTIVE,0 ;device active flag
BITDEF UNIT,STOPPED,2 ;status bit flag for unit stopped
*****************************************************************************
* These will be local to this program *
*****************************************************************************
ifne PTERMARRAY_SIZE-8
fail 'Commodore has changed PTERMARRAY size'
endc
INFO_LEVEL equ 0
***************************************
;The first executable location. This should return an error in case someone
;tried to run us as a program (instead of loading us as a device).
moveq #-1,d0
rts
;A romtag structure. After your driver is brought in from disk, the
;disk image will be scanned for this structure to discover magic constants
;about you (such as where to start running you from...).
initDevDescript:
dw RTC_MATCHWORD
dl initDevDescript
dl EndCode
db RTF_AUTOINIT ;RT_FLAGS
db PVERSION
db NT_DEVICE
db cdPri ;RT_PRI
dl cdName
dl cdIDString
dl DevInit ;RT_INIT
cdName: PARDEVNAME ;This is the name that the device will have
;This is an identifier tag to help in supporting the device
;format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
cdIDString:
PARIDENT
;The romtag specified that we were "RTF_AUTOINIT". This means that the
;RT_INIT structure member points to one of these tables below. If the
;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
DevInit:
dl dev_SizeOf ;data space size
dl funcTable ;pointer to function initializers
dl dataTable ;pointer to data initializers
dl initRoutine ;routine to run
funcTable:
dl Open ;standard system routines
dl Close
dl Expunge
dl ExtFunc ;Reserved for future use!
dl BeginIO ;my device definitions
dl AbortIO
dl -1 ;function table end marker
;The data table initializes static data structures. The format is
;specified in exec/InitStruct routine's manual pages. The
;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
;The first argument is the offset from the device base for this
;byte/word/long. The second argument is the value to put in that cell.
;The table is null terminated
dataTable:
INITBYTE LH_TYPE,NT_DEVICE
INITLONG LN_NAME,cdName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,PVERSION
INITWORD LIB_REVISION,PREVISION
INITLONG LIB_IDSTRING,cdIDString
dl 0 ;terminate list
;This routine gets called after the device has been allocated. The device
;pointer is in D0. The AmigaDOS segment list is in a0. If it returns the
;device pointer, then the device will be linked into the device list. If it
;returns NULL, then the device will be unloaded.
;
;This call is single-threaded by exec; please read the description for
;"Open" below.
;
; Register Usage
; ==============
; a3 -- Points to temporary RAM
; a4 -- Expansion library base
; a5 -- device pointer
; a6 -- Exec base
initRoutine: movea.l d0,a1 ;get device pointer
move.l a0,(dev_SegList,a1) ;save a pointer to our loaded code
rts
;Here begins the system interface commands. When the user calls OpenDevice/
;CloseDevice/RemDevice, this eventually gets translated into a call to the
;following routines (Open/Close/Expunge). Exec has already put our device
;pointer in a6 for us.
;
;Open sets the IO_ERROR field on an error. If it was successful, we should
;also set up the IO_UNIT and LN_TYPE fields. exec takes care of setting up
;IO_DEVICE.
;
;NOTE: We must also copy the current prefs for this unit into the user's
;extended iorequest fields.
;
; Register Usage
; ==============
; d0 -- unitnum
; d1 -- flags
; a1 -- iob
; a6 -- Device ptr
Open: pushm d2/a2-a4
PUTDEBUG 1,<10,10,'STARTING NEW DEBUG RUN',10,10>
movea.l a1,a2 ;save the iob
moveq #MD_NUMUNITS,d2 ;see that the unit number is in range
cmp.l d2,d0
bcc.b .openError
move.l d0,d2 ;see if the unit is already initialized
lsl.l #2,d0
lea (dev_Units,a6,d0.l),a4
move.l (a4),d0
beq.b 1$ ;unit not open - so open it
movea.l d0,a0
btst #ioB_SHARED,(pdu_devFlags,a0) ;see if unit allows shared access
beq.b .openError ;error if not
btst #PARB_SHARED,d1 ;see if the open request allows shared access
bne.b .openUnitOK
bra.b .openError ;unit can have only ONE client
1$ bsr InitUnit ;try and conjure up a unit
move.l (a4),d0 ;see if it opened ok
beq.b .openError
.openUnitOK: movea.l d0,a3 ;unit pointer
move.l d0,(IO_UNIT,a2)
addq.w #1,(LIB_OPENCNT,a6) ;mark us as having another customer
addq.w #1,(UNIT_OPENCNT,a3)
bclr #LIBB_DELEXP,(dev_Flags,a6) ;prevent delayed expunges
btst #PARB_SHARED,d1 ;see if the open request allows shared access
beq.b 2$
bset #ioB_SHARED,(pdu_devFlags,a3) ;unit allows shared access
2$ clr.b (IO_ERROR,a2)
btst #PARB_EOFMODE,(IO_PARFLAGS,a2) ;eof enabled mode set ?
beq.b .openEnd
move.l (pdu_TermArray,a3),(IO_PTERMARRAY+PTERMARRAY_0,a2)
move.l (pdu_TermArray+4,a3),(IO_PTERMARRAY+PTERMARRAY_1,a2)
.openEnd: popm d2/a2-a4
rts
.openError: move.b #IOERR_OPENFAIL,(IO_ERROR,a2)
PUTDEBUG 95,<'Open device routine exiting with error'>
bra.b .openEnd
;--------------------------------------------------------------
; --- initunit initializes a device unit and starts up the
; --- associated unit task
;--------------------------------------------------------------
; --- (unit number:D2 scratch:A3 device:A6)
InitUnit: pushm d2/a2/a5-a6
PUTDEBUG 90,<'InitUnit routine called'>
movea.l a6,a5 ;device pointer
movea.l (SysBase).w,a6
move.l #pdu_Sizeof,d0
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
jsr (_LVOAllocMem,a6)
tst.l d0
beq .initUnitEnd
movea.l d0,a3
movea.l a3,a2 ;for InitStruct
moveq #0,d0 ;don't 0 the rest
lea (UnitInitStruct,pc),a1
jsr (_LVOInitStruct,a6)
move.b d2,(pdu_UnitNum,a3) ;initialize unit number
move.l a5,(pdu_Device,a3)
lea (pdu_stack,a3),a0
move.l a0,(pdu_tcb+TC_SPLOWER,a3)
lea (mduStackSize,a0),a0
move.l a0,(pdu_tcb+TC_SPUPPER,a3)
move.l a3,-(a0) ;pass unit pointer on the stack
move.l a0,(pdu_tcb+TC_SPREG,a3)
lea (pdu_tcb,a3),a0
move.l a0,(MP_SIGTASK,a3)
lea (MP_MSGLIST,a3),a0
NEWLIST a0
lea (pdu_tcb,a3),a1
lea (mdTask_Start,pc),a2 ;for AddTask
PUSH a3
suba.l a3,a3
subq.l #1,a3 ;force odd address GURU if the task ever exits
moveq #0,d0
jsr (_LVOAddTask,a6)
POP a3
lsl.l #2,d2
move.l a3,(dev_Units,a5,d2.l) ;put unit pointer into device structure
add.w d2,d2
move.w (hardwareBaseArray,pc,d2.l),(pdu_IOReg,a3)
move.w (hardwareBaseArray+2,pc,d2.l),(pdu_ifrMask,a3)
move.l (hardwareBaseArray+4,pc,d2.l),(pdu_HardwareBase,a3)
move.l a3,(pdu_is+IS_DATA,a3)
move.l #InterruptCode,(pdu_is+IS_CODE,a3)
movea.l (pdu_HardwareBase,a3),a0
move.b (pdu_ifrMask+1,a3),(INTER,a0) ;make sure interrupts are off
move.b #pcrBits,(PERCR,a0) ;set up the controll register (both ports - dosn't matter)
.initUnitEnd: popm d2/a2/a5-a6
rts
;Table of VIA base addresses for the 4 units
hardwareBaseArray:
dw ORA ;register offset from hardware base
dw ierABits ;interrupt flag mask
dl VIA_Base+VIA0 ;base address for hardware unit 0
dw ORB ;register offset from hardware base
dw ierBBits ;interrupt flag mask
dl VIA_Base+VIA0 ;base address for hardware unit 1
dw ORA ;register offset from hardware base
dw ierABits ;interrupt flag mask
dl VIA_Base+VIA1 ;base address for hardware unit 2
dw ORB ;register offset from hardware base
dw ierBBits ;interrupt flag mask
dl VIA_Base+VIA1 ;base address for hardware unit 3
; --- (unitptr:A3 deviceptr:A6)
FreeUnit: movea.l a3,a1
PUTDEBUG 85,<'FreeUnit routine called'>
move.l #pdu_Sizeof,d0
push a6
movea.l (SysBase).w,a6
jsr (_LVOFreeMem,a6)
pop a6
ExtFunc: moveq #0,d0
rts
; --- (unitptr:A3 deviceptr:A6)
ExpungeUnit: push d2
PUTDEBUG 85,<'ExpungeUnit routine called'>
lea (pdu_tcb,a3),a1
push a6
movea.l (SysBase).w,a6
jsr (_LVORemTask,a6)
pop a6
moveq #0,d2
move.b (pdu_UnitNum,a3),d2 ;save the unit number
bsr FreeUnit ;free the unit structure
lsl.l #2,d2
clr.l (dev_Units,a6,d2.l) ;clear the unit vector from the device
pop d2
rts
;There are two different things that might be returned from the Close
;routine. If the device wishes to be unloaded, then Close must return
;the segment list (as given to Init). Otherwise close MUST return NULL.
; ( device:a6, iob:a1 )
Close: pushm a2-a3
PUTDEBUG 80,<'Close device routine called'>
movea.l a1,a2 ;save iob pointer
movea.l (IO_UNIT,a2),a3
moveq #-1,d0 ;make sure that the iob is not used again
move.l d0,(IO_UNIT,a2)
move.l d0,(IO_DEVICE,a2)
subq.w #1,(UNIT_OPENCNT,a3) ;see if the unit is still in use
bne.b .closeDevice
bsr ExpungeUnit
.closeDevice: subq.w #1,(LIB_OPENCNT,a6)
bne.b .closeEnd
btst #LIBB_DELEXP,(pd_Flags,a6)
beq.b .closeEnd
bsr Expunge
.closeEnd: popm a2-a3
rts
;Expunge is called by the memory allocator when the system is low on
;memory.
;
;There are two different things that might be returned from the Expunge
;routine. If the device is no longer open then Expunge may return the
;segment list (as given to Init). Otherwise Expunge may set the
;delayed expunge flag and return NULL.
;
;One other important note: because Expunge is called from the memory
;allocator, it may NEVER Wait() or otherwise take long time to complete.
;
; A6 - library base (scratch)
; D0-D1/A0-A1 - scratch
Expunge: pushm d2/a5/a6
moveq #0,d2
movea.l a6,a5
movea.l (SysBase).w,a6
tst.w (LIB_OPENCNT,a5) ;any users left ?
beq.b 1$
bset #LIBB_DELEXP,(pd_Flags,a5) ;if there then delay the expunge
bra.b .expungeEnd
1$ move.l (dev_SegList,a5),d2
movea.l a5,a1
jsr (_LVORemove,a6) ;unlink from the library list
moveq #0,d0 ;release our memory
movea.l a5,a1
move.w (LIB_NEGSIZE,a5),d0
suba.l d0,a1
add.w (LIB_POSSIZE,a5),d0
jsr (_LVOFreeMem,a6)
.expungeEnd: move.l d2,d0 ;set up our return value
popm d2/a5/a6
rts
;------------------------------------------------------------------------------
;
; Here begins the real device stuff
;
;------------------------------------------------------------------------------
;BeginIO starts all incoming io. The IO is either queued up for the
;unit task or processed immediately.
;
;BeginIO often is given the responsibility of making devices single
;threaded... so two tasks sending commands at the same time don't cause
;a problem. Once this has been done, the command is dispatched via
;PerformIO.
;
;There are many ways to do the threading. This example uses the
;UNITB_ACTIVE bit. Be sure this is good enough for your device before
;using! Any method is ok. If immediate access can not be obtained, the
;request is queued for later processing.
;
;Some IO requests do not need single threading. These can be performed
;immediatley.
;
;IMPORTANT:
; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
; as a flag. If set to NT_MESSAGE, it assumes the request is
; still pending and will wait. If set to NT_REPLYMSG, it assumes the
; request is finished. It's the responsibility of the device driver
; to set the node type to NT_MESSAGE before returning to the user.
;
;Notes: This routine will look at io_command to determine which task
;to use. Break with QUEUEDBRK and Write requests go to the write
;task. Read requests (only) go to the read task.
;Break requests without QUEUEDBRK initiate a write task exception.
;The actual break job is started, and finished, within that exception.
;At the end of the exception, the write task resumes whatever it was
;doing before the break.
;All other requests are performed immediately, i.e. within the caller's
;context.
;
; ( iob: a1, device:a6 )
AbortIO: clr.b (IO_ERROR,a1)
movea.l (IO_UNIT,a1),a0
cmpa.l (pdu_CurrentIOB,a0),a1
bne.b 1$
clr.l (pdu_CurrentIOB,a0)
1$ rts
;This define is used to tell which commands should be handled
;immediately (on the caller's schedule).
;
;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
;Query, and SetParams
;
;Note that this method limits you to just 32 device specific commands,
;which may not be enough.
IMMEDIATES equ %00000000000000000000000111000011
; --------========--------========
; FEDCBA9876543210FEDCBA9876543210
VIATASK equ $0000000C
BeginIO: push a4
clr.b (IO_ERROR,a1)
move.b #NT_MESSAGE,(LN_TYPE,a1)
movea.l (IO_UNIT,a1),a4
move.w (IO_COMMAND,a1),d0
cmpi.w #PDCMD_SETPARAMS,d0
bgt .noCmd
PUTDEBUG 75,<'BeginIO -- got a valid command'>
Disable a0
move.w #IMMEDIATES,d1
btst d0,d1
bne .immediate
move.w #VIATASK,d1
btst d0,d1
bne .queueMsg
btst #UNITB_STOPPED,(UNIT_FLAGS,a4)
bne.b .queueMsg
bset #UNITB_ACTIVE,(UNIT_FLAGS,a4)
beq.b .immediate
.queueMsg: bset #UNITB_INTASK,(UNIT_FLAGS,a4)
bclr #IOB_QUICK,(IO_FLAGS,a1)
Enable a0
movea.l a4,a0
push a6
movea.l (SysBase).w,a6
jsr (_LVOPutMsg,a6)
pop a6
bra.b .end
.immediate: Enable A0
bsr PerformIO
.end: pop a4
rts
.noCmd: move.b #IOERR_NOCMD,(IO_ERROR,a1)
bra.b .end
;Cmdtable is used to look up the address of a routine that will
;implement the device command.
cmdtable:
dw Invalid-cmdtable
dw MyReset-cmdtable
dw Read-cmdtable
dw Read-cmdtable
dw Invalid-cmdtable
dw Clear-cmdtable
dw MyStop-cmdtable
dw Start-cmdtable
dw Flush-cmdtable
dw Query-cmdtable
dw SetParams-cmdtable
PerformIO: pushm a2-a3
movea.l a1,a2
movea.l (pdu_HardwareBase,a4),a3
move.w (IO_COMMAND,a2),d0
ifge INFO_LEVEL-65
push d0
push a1
PUTDEBUG 65,<'PerformIO --- IOB @ $%lx --- Command =%ld'>
addq.w #8,sp
endc
add.w d0,d0
lea (cmdtable,pc),a0
adda.w (0,a0,d0.w),a0
jsr (a0)
; --- (iob:A2 unitptr:A4 device:A6)
TermIO: move.w (IO_COMMAND,a2),d0
move.w #IMMEDIATES,d1
btst d0,d1
bne.b .termIOimmediate
btst #UNITB_INTASK,(UNIT_FLAGS,a4)
bne.b .termIOimmediate
bclr #UNITB_ACTIVE,(UNIT_FLAGS,a4)
.termIOimmediate:
btst #IOB_QUICK,(IO_FLAGS,a2)
bne.b .termIOend
ifge INFO_LEVEL-70
push a2
PUTDEBUG 70,<'TermIO --- Reply msg IOB @ $%lx'>
addq.w #4,sp
endc
movea.l a2,a1
push a6
movea.l (SysBase).w,a6
jsr (_LVOReplyMsg,a6)
pop a6
.termIOend: popm a2-a3
rts
;------------------------------------------------------------------------------
; --- Invalid command sent to this device - return error
; --- Clear - do nothing - not supported
;------------------------------------------------------------------------------
Invalid: move.b #IOERR_NOCMD,(IO_ERROR,a1)
Clear: rts
;------------------------------------------------------------------------------
; --- Reset the hardware for this unit
;------------------------------------------------------------------------------
MyReset: bsr.b Flush
move.b #pcrBits,(PERCR,a3)
move.b (pdu_ifrMask+1,a4),(INTFR,a3)
move.b (pdu_ifrMask+1,a4),(INTER,a3)
rts
;------------------------------------------------------------------------------
; --- Stop the unit
; --- Start the unit
;------------------------------------------------------------------------------
MyStop: bset #UNITB_STOPPED,(UNIT_FLAGS,a4)
clr.l (IO_ACTUAL,a1)
rts
Start: bsr.b InternalStart
movea.l a2,a1
clr.l (IO_ACTUAL,a1)
rts
InternalStart: bclr #UNITB_STOPPED,(UNIT_FLAGS,a4) ;turn processing back on
movea.l a4,a1 ;kick the task to start it moving
moveq #0,d0
move.b (MP_SIGBIT,a4),d1
bset d1,d0
push a6
movea.l (SysBase).w,a6
jsr (_LVOSignal,a6)
pop a6
rts
;------------------------------------------------------------------------------
; --- Flush pulls all io requests off the que and sends them back.
; -- We must be carefull not to destroy work in progress, and also
; -- that we do not let some io requests slip by.
;
; --- Some funny magic goes on with the STOPPED bit in here. Stop is
; -- defined as not being reentrant. We therefore save the old state
; -- of the bit and then restore it later. This keeps us from needing
; -- to DISABLE in flush. It also fails miserably if someone does a
; -- start in the middle of a flush.
;------------------------------------------------------------------------------
Flush: pushm d2/a6
clr.l (pdu_CurrentIOB,a4)
movea.l (SysBase).w,a6
bset #UNITB_STOPPED,(UNIT_FLAGS,a4)
sne d2
Flush_Loop: movea.l a4,a0
jsr (_LVOGetMsg,a6)
tst.l d0
beq.b Flush_End
movea.l d0,a1
move.b #IOERR_ABORTED,(IO_ERROR,a1)
jsr (_LVOReplyMsg,a6)
bra.b Flush_Loop
Flush_End: move.l d2,d0
popm d2/a6
tst.b d0
beq.b 1$
bsr InternalStart
1$ movea.l a2,a1
rts
;------------------------------------------------------------------------------
; --- Query the parallel device unit status
;------------------------------------------------------------------------------
Query: clr.b (IO_PARSTATUS,a1) ;return the current status
rts
;------------------------------------------------------------------------------
; --- Set the parallel device unit parameters
;------------------------------------------------------------------------------
SetParams: btst #UNITB_ACTIVE,(pdu_devFlags,a4)
beq.b .modeIsCorrect
move.b #1,(IO_ERROR,a1)
bra.b .return
.modeIsCorrect: move.b (IO_PARFLAGS,a1),(pdu_IOparFlags,a4)
btst #PARB_EOFMODE,(pdu_IOparFlags,a4)
beq.b .return
move.l (IO_PTERMARRAY+PTERMARRAY_0,a1),(pdu_TermArray_0,a4)
move.l (IO_PTERMARRAY+PTERMARRAY_1,a1),(pdu_TermArray_1,a4)
.return: rts
;------------------------------------------------------------------------------
; --- Read/Write
;------------------------------------------------------------------------------
Read: tst.l (IO_LENGTH,a1)
bne.b .performIO
clr.l (IO_ACTUAL,a1)
rts
.performIO: push a6
PUTDEBUG 50,<'Read/Write'>
move.w (pdu_IOReg,a4),d7
bclr #rwB_NULLMODE,(pdu_devFlags,a4)
bset #IOPARB_ACTIVE,(IO_FLAGS,a1) ;active
move.l (IO_DATA,a1),(pdu_rwBufferLocation,a4) ;initialize buffer pointer
clr.l (pdu_lengthCounter,a4) ;clear buffer counter
move.l a1,(pdu_CurrentIOB,a4) ;store the current IOB structure
tst.l (IO_LENGTH,a1) ;a -1 here means read to eof
bpl.b .notEOFmode
bset #rwB_NULLMODE,(pdu_devFlags,a4)
.notEOFmode: lea (0,a3,d7.w),a0
cmpi.w #CMD_READ,(IO_COMMAND,a1)
beq.b .setDataDirectionIN
.setDataDirectionOUT:
move.b #0,(IOR,a0)
move.b #-1,(DDR,a0)
bra.b .letTheInterruptWork
.setDataDirectionIN:
move.b #0,(IOR,a0) ;just for the hell of it
move.b #0,(DDR,a0)
.letTheInterruptWork:
move.w (pdu_ifrMask,a4),d0
move.b d0,(INTFR,a3) ;clear the interrupt bit
lea (pdu_is,a4),a1
moveq #INTB_EXTER,d0 ;(level 6) interrupt
movea.l (SysBase).w,a6
jsr (_LVOAddIntServer,a6)
Disable
move.w (pdu_ifrMask,a4),d0
ori.w #$80,d0
move.b d0,(INTER,a3) ;enable chip interrupt
move.l (pdu_SigMask,a4),d0
ifge INFO_LEVEL-50
push d0
push (ThisTask,a6)
PUTDEBUG 50,<'Task @ $%lx waiting -- sigmask = $%lx'>
addq.w #8,sp
endc
jsr (_LVOWait,a6) ;sleep while the interrupt does the work
PUTDEBUG 70,<'Got signal'>
Enable
lea (pdu_is,a4),a1
moveq #INTB_EXTER,d0
jsr (_LVORemIntServer,a6) ;remove the interrupt server
PUTDEBUG 50,<'Read/Write finished'>
pop a6
rts
****************************************
*** === INTERRUPT DRIVER === ***
****************************************
InterruptCode: pushm d1-d7/a0-a6
movea.l a1,a4
movea.l (pdu_HardwareBase,a4),a3
move.b (INTFR,a3),d7
and.w (pdu_ifrMask,a4),d7
bne.b .isMine
popm d1-d7/a0-a6
moveq #0,d0
rts
.isMine: move.l (pdu_CurrentIOB,a4),d0
beq .noCurrentIOB
movea.l d0,a1
move.w (pdu_IOReg,a4),d7
.read_write: movea.l (pdu_rwBufferLocation,a4),a0
btst #IOPARB_ABORT,(IO_FLAGS,a1)
bne .rwFINISHED
cmpi.w #CMD_WRITE,(IO_COMMAND,a1)
bne.b .READdata
ifge INFO_LEVEL-200
pea (IOR,a3,d7.w)
moveq #0,d0
move.b (a0),d0
push d0
PUTDEBUG 100,<'Writing byte $%lx to IOR @ $%08lx'>
addq.w #8,sp
endc
move.b (a0)+,(IOR,a3,d7.w)
bne .updateCounters
btst #rwB_NULLMODE,(pdu_devFlags,a4)
beq.b .updateCounters
bra .rwFINISHED
.READdata: move.b (IOR,a3,d7.w),d0
bne.b .notNullCharRead
ifge INFO_LEVEL-200
pea (IOR,a3,d7.w)
andi.l #$ff,d0
push d0
PUTDEBUG 100,<'Read non-zero byte = $%08lx from IOR @ $%lx'>
addq.w #8,sp
endc
btst #rwB_NULLMODE,(pdu_devFlags,a4)
bne .rwFINISHED
.notNullCharRead:
movea.l (pdu_rwBufferLocation,a4),a0
move.b d0,(a0)+
.updateCounters:
move.l a0,(pdu_rwBufferLocation,a4)
addq.l #1,(pdu_lengthCounter,a4)
btst #PARB_EOFMODE,(IO_PARFLAGS,a1) ;test EOF mode enabled bit in IOB
beq.b .noTermArraySet
lea (IO_PTERMARRAY+PTERMARRAY_0,a1),a0
moveq #8-1,d1
.checkForTermMatch:
cmp.b (a0)+,d0
dbcc d1,.checkForTermMatch
beq.b .rwFINISHED
.noTermArraySet:
move.l (IO_LENGTH,a1),d0
bmi .rwUntilNullTerm
cmp.l (pdu_lengthCounter,a4),d0
bgt .rwUntilNullTerm
.rwFINISHED: move.l (pdu_lengthCounter,a4),(IO_ACTUAL,a1)
bclr #IOPARB_ACTIVE,(IO_FLAGS,a1) ;clear request queued or current bit
.noCurrentIOB: bclr #rwB_NULLMODE,(pdu_devFlags,a4)
bclr #DEVB_ACTIVE,(pdu_devFlags,a4)
clr.l (pdu_CurrentIOB,a4)
movea.l (SysBase).w,a6
move.l (pdu_SigMask,a4),d0
lea (pdu_tcb,a4),a1
ifge INFO_LEVEL-50
push d0
push a0
PUTDEBUG 65,<'Signaling task @ $%lx with signal $%lx'>
addq.w #8,sp
endc
jsr (_LVOSignal,a6)
move.b (pdu_ifrMask+1,a4),(INTER,a3) ;disable chip interrupt
.rwUntilNullTerm:
popm d1-d7/a0-a6
moveq #1,d0 ;terminate the interrupt chain
rts
;------------------------------------------------------------------------------
; --- Sub-task related stuff
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
; Register Usage
; A6 = exec pointer
; A5 = device pointer
; A4 = unit pointer
; D7 = wait mask
;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
mdTask_Start: movea.l (SysBase).w,a6
movea.l (4,sp),a4 ;unit pointer
movea.l (pdu_Device,a4),a5 ;device pointer
moveq #-1,d0 ;-1 is any signal at all
jsr (_LVOAllocSignal,a6)
moveq #0,d7
bset d0,d7
move.l d7,(pdu_SigMask,a4) ;signal for when interrupt is finished
moveq #-1,d0 ;-1 is any signal at all
jsr (_LVOAllocSignal,a6)
move.b d0,(MP_SIGBIT,a4)
move.b #PA_SIGNAL,(MP_FLAGS,a4)
moveq #0,d7
bset d0,d7
bra.b .checkStatus
.unlock: andi.b #$FF&(~(UNITB_ACTIVE!UNITB_INTASK)),(UNIT_FLAGS,a4)
.mainLoop: move.l d7,d0
jsr (_LVOWait,a6)
.checkStatus: btst #UNITB_STOPPED,(UNIT_FLAGS,a4) ;see if we are stopped
bne.b .mainLoop
bset #UNITB_ACTIVE,(UNIT_FLAGS,a4)
bne.b .mainLoop ;device in use
.nextMessage: movea.l a4,a0
jsr (_LVOGetMsg,a6)
tst.l d0
beq.b .unlock ;no message ?
movea.l d0,a1 ;IOB
exg a5,a6 ;put the device pointer in right register
bsr PerformIO
PUTDEBUG 100,<'Unit Task --- returned from PerformIO'>
exg a5,a6 ;get exec back in A6
bra.b .nextMessage
*******************************************************************************
UnitInitStruct:
INITBYTE LH_TYPE,NT_DEVICE
INITBYTE LIB_FLAGS,LIBF_CHANGED
INITWORD LIB_VERSION,PVERSION
INITWORD LIB_REVISION,PREVISION
INITBYTE pdu_is+LN_TYPE,NT_INTERRUPT
dc.l 0
;------------------------------------------------------------------------------
;EndCode is a marker that shows the end of your code. Make sure that it
;does not span sections nor is before the rom tag in memory! It is ok to
;put it right after the rom tag -- that way you are always safe. I put it
;here because it is the right thing to do, and i know that it is safe in
;this case
;------------------------------------------------------------------------------
ISDEBUG 'eightbit'
EndCode:
*******************************************************************************
end